#!/usr/bin/python3
import sys
from collections import deque

def boundary(elves):
    minx = miny = sys.maxsize
    maxx = maxy = 0
    for ex, ey in elves:
        minx = min(minx, ex)
        miny = min(miny, ey)
        maxx = max(maxx, ex)
        maxy = max(maxy, ey)
    return minx, miny, maxx, maxy

def print_locations(elves):
    minx, miny, maxx, maxy = boundary(elves)
    for y in range(miny, maxy + 1):
        for x in range(minx, maxx + 1):
            print('#' if (x, y) in elves else '.', end='')
        print()

def count_ground_tiles(elves):
    minx, miny, maxx, maxy = boundary(elves)
    count = 0
    for y in range(miny, maxy + 1):
        for x in range(minx, maxx + 1):
            count += 1 if (x, y) not in elves else 0
    return count

def solution(endless=True, rounds=None):
    elves = set()
    y = 0
    for line in sys.stdin:
        stripped = line.strip()
        if len(stripped) == 0: continue
        [elves.add((x, y)) for x in range(len(stripped)) if stripped[x] == '#']
        y += 1
    print(elves)
    #print_locations(elves)

    NW = lambda pair: (pair[0] - 1, pair[1] - 1)
    NO = lambda pair: (pair[0], pair[1] - 1)
    NE = lambda pair: (pair[0] + 1, pair[1] - 1)
    SW = lambda pair: (pair[0] - 1, pair[1] + 1)
    SO = lambda pair: (pair[0], pair[1] + 1)
    SE = lambda pair: (pair[0] + 1, pair[1] + 1)
    WE = lambda pair: (pair[0] - 1, pair[1])
    EA = lambda pair: (pair[0] + 1, pair[1])

    considerations = deque([(NW, NO, NE), (SW, SO, SE), (NW, WE, SW), (NE, EA, SE)])
    r = 1
    while True:
        proposals = []
        proposal_count = {}
        for elf in elves:
            alone = True
            for rules in considerations:
                for subrules in rules:
                    if subrules(elf) in elves:
                        alone = False
            if alone:
                #print(elf, 'alone')
                continue
            for rules in considerations:
                #print(elf, 'looking at', rules[0](elf), rules[1](elf), rules[2](elf))
                p0 = rules[0](elf)
                p1 = rules[1](elf)
                p2 = rules[2](elf)
                if p0 not in elves and p1 not in elves and p2 not in elves:
                    #print(elf, 'proposing', rules[1](elf))
                    proposals.append((elf, p1))
                    if p1 not in proposal_count:
                        proposal_count[p1] = 1
                    else:
                        proposal_count[p1] += 1
                    break

        #print(len(proposals), 'proposals')
        #print(proposal_count)

        moves = 0
        considerations.rotate(-1)
        for proposal in proposals:
            elf, next_elf = proposal
            if proposal_count[next_elf] == 1:
                elves.remove(elf)
                elves.add(next_elf)
                moves += 1

        print_locations(elves)
        print(f'{moves} elves moved')
        print(f'found {count_ground_tiles(elves)} ground tiles (round {r})')

        r += 1
        if not endless and r > rounds: break
        if moves == 0: break

if sys.argv[1] in '1':
    solution(endless=False, rounds=10)
else:
    solution()
